﻿using System;
using System.Collections.Generic;
using QuantumNet.Base.Interfaces;
using QuantumNet.Extensions;

namespace QuantumNet.Mathematics.Probability
{
    public class BetaDistribution<T,A> : QuantumNet.Mathematics.Probability.Interfaces.IContinuousDistribution<T> where A:IReal<T>,new()
    {

        private static readonly A Wrapper = new A();

        public T Alpha { get; set; }

        public T Beta { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Object"/> class.
        /// </summary>
        public BetaDistribution(T alpha, T beta)
        {
            Alpha = alpha;
            Beta = beta;
        }

        #region Implementation of IDistribution<T>

        public T Variance
        {
            get
            {
                return Wrapper.Divide(Wrapper.Multiply(Alpha, Beta),
                                      Wrapper.Multiply(Wrapper.Pow(Wrapper.Add(Alpha, Beta), 2.CastTo<T>()),
                                                       Wrapper.Add(Wrapper.Add(Alpha, Beta), Wrapper.One())));
            }
        }

        public T Sigma
        {
            get { return Wrapper.Sqrt(Variance); }
        }

        public T Entropy
        {
            get { throw new NotImplementedException(); }
        }

        public T Skewness
        {
            get
            {
                return
                    Wrapper.Divide(
                        Wrapper.Multiply(Wrapper.Multiply(2.CastTo<T>(), Wrapper.Subtract(Beta, Alpha)),
                                         Wrapper.Sqrt(Wrapper.Add(Wrapper.Add(Alpha, Beta), Wrapper.One()))),
                        Wrapper.Sqrt(Wrapper.Multiply(Alpha, Beta)));
            }
        }

        public T UnnormalizedKurtosis
        {
            get { return Wrapper.Add(NormalizedKurtosis,3.CastTo<T>()); }
        }

        public T NormalizedKurtosis
        {
            get
            {
                return
                    Wrapper.Divide(
                        Wrapper.Add(
                            Wrapper.Prod(new List<T>
                                             {
                                                 3.CastTo<T>(),
                                                 Wrapper.Sum(new List<T> {Alpha, Beta, Wrapper.One()}),
                                                 2.CastTo<T>(),
                                                 Wrapper.Pow(Wrapper.Add(Alpha, Beta), 2.CastTo<T>())
                                             }),
                            Wrapper.Prod(new List<T>
                                             {Alpha, Beta, Wrapper.Subtract(Wrapper.Add(Alpha, Beta), 6.CastTo<T>())})),
                        Wrapper.Subtract(
                            Wrapper.Prod(new List<T>
                                             {
                                                 Alpha,
                                                 Beta,
                                                 Wrapper.Sum(new List<T> {Alpha, Beta, 2.CastTo<T>()}),
                                                 Wrapper.Sum(new List<T> {Alpha, Beta, 3.CastTo<T>()})
                                             }), 3.CastTo<T>()));
            }
        }

        public T Esperance
        {
            get { return Wrapper.Divide(Alpha,Wrapper.Add(Alpha,Beta)); }
        }

        public T CumulativeDistribution(T x)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Implementation of IContinuousDistribution<T>

        public T Mode
        {
            get
            {
                return Wrapper.IsGreater(Alpha, Wrapper.One()) && Wrapper.IsGreater(Beta, Wrapper.One())
                           ? Wrapper.Divide(Wrapper.Subtract(Alpha, Wrapper.One()),
                                            Wrapper.Subtract(Wrapper.Add(Alpha, Beta), 2.CastTo<T>()))
                           : Wrapper.Zero();
            }
        }

        public T Maximum
        {
            get {return Wrapper.One(); }
        }

        public T Minimum
        {
            get { return Wrapper.Zero(); }
        }

        public T Median
        {
            get { throw new NotImplementedException(); }
        }

        public T Density
        {
            get { throw new NotImplementedException(); }
        }

        #endregion
    }

    
}
